package mosdi.discovery.strategies;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import mosdi.discovery.EvaluatedPattern;
import mosdi.discovery.ObjectiveFunction;
import mosdi.discovery.ScoreAndPValue;
import mosdi.discovery.MotifFinder.SearchSpecification;
import mosdi.discovery.MotifFinder.SearchState;

// TODO: Remove and implement functionality of having an initialPValueThreshold into OptimumSearch
public class SingleObjectiveOptimumSearch implements SearchSpecification {
	private ObjectiveFunction objective;
	private List<EvaluatedPattern> bestPatterns;
	private double bestScore;
	private SearchState searchState;
	private double initialPValueThreshold;
	
	public SingleObjectiveOptimumSearch(ObjectiveFunction objective) {
		this.objective = objective;
		this.initialPValueThreshold = 1.0;
	}

	public SingleObjectiveOptimumSearch(ObjectiveFunction objective, double initialPValueThreshold) {
		this.objective = objective;
		this.initialPValueThreshold = initialPValueThreshold;
	}

	@Override
	public boolean check(int prefixLength, int[] nodes) {
		return -Math.log(objective.pValueLowerBound(prefixLength, nodes)) >= bestScore;
	}

	@Override
	public void evaluateCandidate(int[] nodes) {
		ScoreAndPValue s;
		s = objective.evaluate(nodes, Math.exp(-bestScore));
		if ((s!=null) && !Double.isNaN(s.getMinusLogPValue())) {
			if (s.getMinusLogPValue()>=bestScore) {
				if (s.getMinusLogPValue()>bestScore) bestPatterns.clear();
				EvaluatedPattern e = new EvaluatedPattern(searchState.getPattern(),s); 
				bestPatterns.add(e);
				bestScore = s.getMinusLogPValue();
			}
		}
	}

	@Override
	public Collection<EvaluatedPattern> getResults() {
		return bestPatterns;
	}

	@Override
	public void initialize(SearchState searchState) {
		this.searchState = searchState;
		bestScore = -Math.log(initialPValueThreshold);
		bestPatterns = new ArrayList<EvaluatedPattern>();
		objective.initialize(searchState);
	}

	@Override
	public void updatePattern(int newCharacter, int leftmostChangedPosition) {
		objective.updatePattern(newCharacter, leftmostChangedPosition);
	}

}
